package com.ndood.api.domain.record.receive.v1.service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.SortedMap;

import org.apache.http.util.Asserts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.alipay.api.response.AlipayTradeCancelResponse;
import com.alipay.api.response.AlipayTradePayResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.ndood.api.app.tools.IdUtils;
import com.ndood.api.base.dao.record_receive.v1.ExtendRecoRecOfflineOrderDao;
import com.ndood.api.base.dao.record_receive.v1.ExtendRecoRecPayDao;
import com.ndood.api.domain.record.receive.v1.entity.dto.RecoRecFlowDto;
import com.ndood.api.domain.record.receive.v1.entity.dto.RecoRecOfflineOrderDto;
import com.ndood.api.domain.record.receive.v1.entity.dto.RecoRecPayDto;
import com.ndood.api.domain.record.receive.v1.repository.RecoRecFlowRepository;
import com.ndood.api.domain.record.receive.v1.repository.RecoRecOfflineOrderRepository;
import com.ndood.api.domain.record.receive.v1.repository.RecoRecPayRepository;
import com.ndood.api.domain.support.merchant.entity.dto.SupportMchRecChannelDto;
import com.ndood.api.domain.support.merchant.entity.dto.SupportMchRecContractDto;
import com.ndood.api.domain.support.merchant.service.SupportMchRecContractService;
import com.ndood.api.domain.support.staff.entity.dto.SupportStaffDto;
import com.ndood.common.base.constaints.CommonConstaints;
import com.ndood.common.base.util.BigDecimalUtil;
import com.ndood.common.base.util.DateUtil;
import com.ndood.common.base.util.StringUtil;

/**
 * 收款记录-平台线下官方支付宝-当面付订单记录服务
 * 记账服务的职责是将支付结果和交易流水持久化
 */
@Service
public class RecoRecPlatformOfflineOfficialAlif2fService {
	
	@Autowired
	private RecoRecOfflineOrderRepository recoRecOfflineOrderRepository;
	
	@Autowired
	private RecoRecPayRepository recoRecPayRepository;
	
	@Autowired
	private ExtendRecoRecPayDao extendRecoRecPayDao;
	
	@Autowired
	private ExtendRecoRecOfflineOrderDao extendRecoRecOfflineOrderDao;
	
	@Autowired
	private IdUtils idUtils;
	
	@Autowired
	private RecoRecFlowRepository recoRecFlowRepository;
	
	@Autowired
	private SupportMchRecContractService supportMchRecContractService;
	
	/**
	 * 1 记录扫码预支付成功
	 */
	@Transactional
	public RecoRecOfflineOrderDto preCreateSuccess(String orderNo, String payOrderNo, String subject, String storeId,
			String expireTime, String notifyUrl, String amount, String payRemark, String deviceNo, String ip, SupportStaffDto staff,
			SupportMchRecChannelDto channel, AlipayTradePrecreateResponse response) {
		
		// Step1: 解析参数
		String qrcode = response.getQrCode();
		
		// Step2: 生成订单
		RecoRecOfflineOrderDto o = new RecoRecOfflineOrderDto();
		o.setOrderNo(orderNo);
		o.setAgentId(staff.getAgentId());
		o.setAgentName(staff.getAgentName());
		o.setMchId(staff.getMchId());
		o.setMchName(staff.getMerchantName());
		o.setShopId(staff.getShopId());
		o.setShopName(staff.getShopName());
		o.setClientIp(ip);
		o.setDeviceNo(deviceNo);
		o.setSubject(subject);
		o.setExpireTime(expireTime);
		o.setPayCashierId(staff.getId());
		o.setPayCashierName(staff.getNickName()==null?staff.getMobile()==null?staff.getEmail():staff.getMobile():staff.getNickName());
		o.setPayRemark(payRemark);
		o.setTotalAmount(new BigDecimal(amount));
		o.setFreeAmount(new BigDecimal(0));
		o.setReceiptAmount(o.getFreeAmount());
		o.setRefundAmount(o.getFreeAmount());
		o.setReceiptRefundAmount(o.getFreeAmount());
		o.setCanRefundAmount(o.getFreeAmount());
		o.setStatus(CommonConstaints.REC_ORDER_STATUS_PAYING);
		o.setParam1(StringUtil.substring(qrcode, 50));
		recoRecOfflineOrderRepository.insertRecOfflineOrder(o);
		
		// Step3: 生成支付订单
		RecoRecPayDto p = new RecoRecPayDto();
		p.setPayOrderNo(payOrderNo);
		p.setOrderNo(orderNo);
		p.setPayWay(channel.getPayWay());
		p.setPayType(channel.getPayType());
		p.setContractId(channel.getContractId());
		p.setContractNo(channel.getContractNo());
		p.setContractType(channel.getContractType());
		p.setContractName(channel.getContractName());
		p.setProductNo(channel.getProductNo());
		p.setProductName(channel.getProductName());
		p.setChannelId(channel.getId());
		p.setChannelNo(channel.getChannelNo());
		p.setChannelName(channel.getChannelName());
		p.setTotalAmount(o.getTotalAmount());
		p.setFreeAmount(new BigDecimal(0));
		p.setReceiptAmount(p.getFreeAmount());
		p.setThirdFreeAmount(p.getFreeAmount());
		p.setBuyerPayAmount(p.getFreeAmount());
		p.setStatus(CommonConstaints.REC_CHANNEL_PAY_STATUS_CREATE);
		p.setParam1(StringUtil.substring(o.getParam1(), 50));
		recoRecPayRepository.insertRecPay(p);
		return o;
	}

	/**
	 * 2 记录扫码预支付失败
	 */
	@Transactional
	public RecoRecOfflineOrderDto preCreateFail(String orderNo, String payOrderNo, String subject, String storeId,
			String expireTime, String notifyUrl, String amount, String payRemark, String deviceNo, String ip, SupportStaffDto staff,
			SupportMchRecChannelDto channel, AlipayTradePrecreateResponse response) {
		
		// Step1: 解析参数
		String subCode = response.getSubCode();
		String subMsg = response.getSubMsg();
		
		RecoRecOfflineOrderDto o = new RecoRecOfflineOrderDto();
		o.setOrderNo(orderNo);
		o.setAgentId(staff.getAgentId());
		o.setAgentName(staff.getAgentName());
		o.setMchId(staff.getMchId());
		o.setMchName(staff.getMerchantName());
		o.setShopId(staff.getShopId());
		o.setShopName(staff.getShopName());
		o.setClientIp(ip);
		o.setDeviceNo(deviceNo);
		o.setSubject(subject);
		o.setExpireTime(expireTime);
		o.setPayCashierId(staff.getId());
		o.setPayCashierName(staff.getNickName()==null?staff.getMobile()==null?staff.getEmail():staff.getMobile():staff.getNickName());
		o.setPayRemark(payRemark);
		o.setTotalAmount(new BigDecimal(amount));
		o.setReceiptAmount(new BigDecimal(0));
		o.setFreeAmount(o.getTotalAmount());
		o.setRefundAmount(o.getFreeAmount());
		o.setReceiptRefundAmount(o.getFreeAmount());
		o.setCanRefundAmount(o.getFreeAmount());
		o.setStatus(CommonConstaints.REC_ORDER_STATUS_FAILED);
		o.setParam1(StringUtil.substring(subCode, 50));
		o.setParam2(StringUtil.substring(subMsg, 50));
		recoRecOfflineOrderRepository.insertRecOfflineOrder(o);
		
		// Step3: 生成支付订单
		RecoRecPayDto p = new RecoRecPayDto();
		p.setPayOrderNo(payOrderNo);
		p.setOrderNo(orderNo);
		p.setPayWay(channel.getPayWay());
		p.setPayType(channel.getPayType());
		p.setContractId(channel.getContractId());
		p.setContractNo(channel.getContractNo());
		p.setContractType(channel.getContractType());
		p.setContractName(channel.getContractName());
		p.setProductNo(channel.getProductNo());
		p.setProductName(channel.getProductName());
		p.setChannelId(channel.getId());
		p.setChannelNo(channel.getChannelNo());
		p.setChannelName(channel.getChannelName());
		p.setTotalAmount(o.getTotalAmount());
		p.setFreeAmount(new BigDecimal(0));
		p.setReceiptAmount(p.getFreeAmount());
		p.setThirdFreeAmount(p.getFreeAmount());
		p.setBuyerPayAmount(p.getFreeAmount());
		p.setStatus(CommonConstaints.REC_CHANNEL_PAY_STATUS_FAILED);
		p.setParam1(o.getParam1());
		p.setParam2(o.getParam2());
		recoRecPayRepository.insertRecPay(p);
		return o;
	}

	/**
	 * 3 记录异步通知结果，通知成功记录订单，通知失败不处理
	 */
	@Transactional
	public RecoRecOfflineOrderDto preCreateNotify(String channelNo, Integer contractType, Integer merchantId,
			SortedMap<String, Object> params) throws Exception {
		// Step1: 获取参数
		String app_id = (String) params.get("app_id");
		String buyer_id = (String) params.get("buyer_id");
		String buyer_logon_id = (String) params.get("buyer_logon_id");
		String receipt_amount = (String) params.get("receipt_amount");
		String buyer_pay_amount = (String) params.get("buyer_pay_amount");
		String gmt_payment = (String) params.get("gmt_payment");
		String out_trade_no = (String) params.get("out_trade_no");
		String trade_status = (String) params.get("trade_status");
		Asserts.notNull(trade_status, "交易状态为空！");
		Asserts.notNull(out_trade_no, "渠道订单号为空！");
		if (!"TRADE_SUCCESS".equals(trade_status)) { 
			// TRADE_CLOSED TRADE_FINISHED TRADE_SUCCESS WAIT_BUYER_PAY
			// 只要不是SUCCESS都不处理，直接返回NULL，系统会定时撤销订单
			return null;
		}
		
		// Step2: 查询订单
		String payOrderNo = out_trade_no;
		RecoRecPayDto p = extendRecoRecPayDao.extendFindReceivePayByPayOrderNo(payOrderNo);
		Asserts.notNull(p, "渠道订单不存在！");
		RecoRecOfflineOrderDto o = extendRecoRecOfflineOrderDao.extendFindOfflineOrderByOrderNo(p.getOrderNo());
		Asserts.notNull(o, "订单不存在！");
		if(!CommonConstaints.REC_ORDER_STATUS_PAYING.equals(o.getStatus())) {
			// 只处理支付中的订单
			return null;
		}

		// Step3: 提取出关键变量并进行计算
		p.setParam1(app_id);
		p.setPayTime(gmt_payment);
		p.setReceiptAmount(new BigDecimal(receipt_amount)); // 商户实收
		p.setFreeAmount(BigDecimalUtil.sub(p.getTotalAmount(), p.getReceiptAmount())); // 商户优惠 = 总金额 - 商户实收
		p.setBuyerPayAmount(new BigDecimal(buyer_pay_amount)); // 买家实付
		p.setThirdFreeAmount(BigDecimalUtil.sub(p.getReceiptAmount(), p.getBuyerPayAmount())); // 接口优惠 = 商户实收 - 买家实付
		p.setBuyerLogonId(buyer_logon_id);
		p.setBuyerUserId(buyer_id);
		p.setStatus(CommonConstaints.REC_CHANNEL_PAY_STATUS_SUCCESS);
		recoRecPayRepository.updateRecPay(p);
		
		o.setReceiptAmount(p.getReceiptAmount());
		o.setCanRefundAmount(o.getTotalAmount());
		o.setFreeAmount(p.getFreeAmount());
		o.setLastPayTime(gmt_payment);
		o.setParam1(app_id);
		o.setStatus(CommonConstaints.REC_ORDER_STATUS_SUCCESS);
		o.setPay(p);
		recoRecOfflineOrderRepository.updateRecOfflineOrder(o);
		
		// Step4: 支付成功记录交易流水
		RecoRecFlowDto flow = new RecoRecFlowDto();
		flow.setFlowNo(idUtils.getNextId());
		flow.setTradeNo(p.getPayOrderNo());
		flow.setAgentId(o.getAgentId());
		flow.setAgentName(o.getAgentName());
		flow.setChannelId(p.getChannelId());
		flow.setChannelName(p.getChannelName());
		flow.setChannelNo(p.getChannelNo());
		flow.setContractId(p.getContractId());
		flow.setContractName(p.getContractName());
		flow.setContractNo(p.getContractNo());
		flow.setContractType(p.getContractType());
		flow.setMchId(o.getMchId());
		flow.setMchName(o.getMchName());
		flow.setOrderNo(o.getOrderNo());
		flow.setPayType(p.getPayType());
		flow.setPayWay(p.getPayWay());
		flow.setProductName(p.getProductName());
		flow.setProductNo(p.getProductNo());
		flow.setShopId(o.getShopId());
		flow.setShopName(o.getShopName());
		flow.setTradeAmount(p.getTotalAmount());
		flow.setTradeTime(p.getPayTime());
		flow.setTradeType(CommonConstaints.TRADE_TYPE_REC_PAY);
		
		// 查询出支付商户合同信息
		SupportMchRecContractDto contract = supportMchRecContractService.getMerchantReceiveContract(p.getContractId());
		Assert.notNull(contract, "商户收款合同不存在");
		
		flow.setSettleStatus(CommonConstaints.SETTLE_STATUS_INIT);
		flow.setSettleType(contract.getSettleType());
		flow.setSettleRate(contract.getRate());
		flow.setSettleRiskDay(contract.getRiskDay());
		flow.setSettleDate(DateUtil.getAfterDate(new Date(), 0, flow.getSettleRiskDay(), 0, 0, 0));
		if(CommonConstaints.SETTLE_TYPE_SOLID.equals(flow.getSettleType())){
			flow.setSettleAgentRate(new BigDecimal(0));
			flow.setSettlePlatformRate(new BigDecimal(0));
			flow.setSettleAgentFee(contract.getAgentFee()); 
			flow.setSettlePlatformFee(contract.getPlatformFee());
			flow.setSettlePlatformProfit(flow.getSettlePlatformFee());
			flow.setSettleAgentProfit(flow.getSettleAgentFee());
		} else {
			flow.setSettleAgentFee(new BigDecimal(0)); 
			flow.setSettlePlatformFee(new BigDecimal(0));
			flow.setSettleAgentRate(contract.getAgentRate());
			flow.setSettlePlatformRate(contract.getPlatformRate());
			flow.setSettlePlatformProfit(BigDecimalUtil.mul(flow.getTradeAmount(), flow.getSettlePlatformRate()));
			flow.setSettleAgentProfit(BigDecimalUtil.mul(flow.getTradeAmount(), flow.getSettleAgentRate()));
		}
		flow.setSettleProfit(BigDecimalUtil.mul(flow.getTradeAmount(), contract.getRate()));
		flow.setSettleMchProfit(BigDecimalUtil.sub(flow.getTradeAmount(), BigDecimalUtil.add(flow.getSettlePlatformProfit(), flow.getSettleAgentProfit())));
		recoRecFlowRepository.insertRecFlow(flow);	
		return o;
	}

	/**
	 * 4 记录条形码支付支付中订单
	 */
	@Transactional
	public RecoRecOfflineOrderDto barCodePaying(String barCode, String orderNo, String payOrderNo, String subject, String storeId,
			String expireTime, String amount, String payRemark, String deviceNo, String ip, SupportStaffDto staff,
			SupportMchRecChannelDto channel, AlipayTradePayResponse response) {
		
		// Step1: 生成订单
		RecoRecOfflineOrderDto o = new RecoRecOfflineOrderDto();
		o.setOrderNo(orderNo);
		o.setAgentId(staff.getAgentId());
		o.setAgentName(staff.getAgentName());
		o.setMchId(staff.getMchId());
		o.setMchName(staff.getMerchantName());
		o.setShopId(staff.getShopId());
		o.setShopName(staff.getShopName());
		o.setClientIp(ip);
		o.setDeviceNo(deviceNo);
		o.setSubject(subject);
		o.setExpireTime(expireTime);
		o.setPayCashierId(staff.getId());
		o.setPayCashierName(staff.getNickName()==null?staff.getMobile()==null?staff.getEmail():staff.getMobile():staff.getNickName());
		o.setPayRemark(payRemark);
		o.setTotalAmount(new BigDecimal(amount));
		o.setFreeAmount(new BigDecimal(0));
		o.setReceiptAmount(o.getFreeAmount());
		o.setRefundAmount(o.getFreeAmount());
		o.setReceiptRefundAmount(o.getFreeAmount());
		o.setCanRefundAmount(o.getFreeAmount());
		o.setStatus(CommonConstaints.REC_ORDER_STATUS_PAYING);
		o.setParam1(barCode);
		recoRecOfflineOrderRepository.insertRecOfflineOrder(o);
		
		// Step3: 生成支付订单
		RecoRecPayDto p = new RecoRecPayDto();
		p.setPayOrderNo(payOrderNo);
		p.setOrderNo(orderNo);
		p.setPayWay(channel.getPayWay());
		p.setPayType(channel.getPayType());
		p.setContractId(channel.getContractId());
		p.setContractNo(channel.getContractNo());
		p.setContractType(channel.getContractType());
		p.setContractName(channel.getContractName());
		p.setProductNo(channel.getProductNo());
		p.setProductName(channel.getProductName());
		p.setChannelId(channel.getId());
		p.setChannelNo(channel.getChannelNo());
		p.setChannelName(channel.getChannelName());
		p.setTotalAmount(o.getTotalAmount());
		p.setFreeAmount(new BigDecimal(0));
		p.setReceiptAmount(p.getFreeAmount());
		p.setThirdFreeAmount(p.getFreeAmount());
		p.setBuyerPayAmount(p.getFreeAmount());
		p.setStatus(CommonConstaints.REC_CHANNEL_PAY_STATUS_CREATE);
		p.setParam1(o.getParam1());
		recoRecPayRepository.insertRecPay(p);
		return o;
	}
	
	/**
	 * 5 记录条形码支付失败订单
	 */
	@Transactional
	public RecoRecOfflineOrderDto barCodeFail(String barCode, String orderNo, String payOrderNo, String subject, String storeId,
			String expireTime, String amount, String payRemark, String deviceNo, String ip, SupportStaffDto staff,
			SupportMchRecChannelDto channel, AlipayTradePayResponse response) {
		// Step1: 解析参数
		String subCode = response.getSubCode();
		String subMsg = response.getSubMsg();
		
		// Step2: 条码支付失败
		RecoRecOfflineOrderDto o = new RecoRecOfflineOrderDto();
		o.setOrderNo(orderNo);
		o.setAgentId(staff.getAgentId());
		o.setAgentName(staff.getAgentName());
		o.setMchId(staff.getMchId());
		o.setMchName(staff.getMerchantName());
		o.setShopId(staff.getShopId());
		o.setShopName(staff.getShopName());
		o.setClientIp(ip);
		o.setDeviceNo(deviceNo);
		o.setSubject(subject);
		o.setExpireTime(expireTime);
		o.setPayCashierId(staff.getId());
		o.setPayCashierName(staff.getNickName()==null?staff.getMobile()==null?staff.getEmail():staff.getMobile():staff.getNickName());
		o.setPayRemark(payRemark);
		o.setTotalAmount(new BigDecimal(amount));
		o.setFreeAmount(new BigDecimal(0));
		o.setReceiptAmount(o.getFreeAmount());
		o.setRefundAmount(o.getFreeAmount());
		o.setReceiptRefundAmount(o.getFreeAmount());
		o.setCanRefundAmount(o.getFreeAmount());
		o.setStatus(CommonConstaints.REC_ORDER_STATUS_FAILED);
		o.setParam1(subCode);
		o.setParam2(subMsg);
		recoRecOfflineOrderRepository.insertRecOfflineOrder(o);
		
		// Step3: 生成支付订单
		RecoRecPayDto p = new RecoRecPayDto();
		p.setPayOrderNo(payOrderNo);
		p.setOrderNo(orderNo);
		p.setPayWay(channel.getPayWay());
		p.setPayType(channel.getPayType());
		p.setContractId(channel.getContractId());
		p.setContractNo(channel.getContractNo());
		p.setContractType(channel.getContractType());
		p.setContractName(channel.getContractName());
		p.setProductNo(channel.getProductNo());
		p.setProductName(channel.getProductName());
		p.setChannelId(channel.getId());
		p.setChannelNo(channel.getChannelNo());
		p.setChannelName(channel.getChannelName());
		p.setTotalAmount(o.getTotalAmount());
		p.setFreeAmount(new BigDecimal(0));
		p.setReceiptAmount(p.getFreeAmount());
		p.setThirdFreeAmount(p.getFreeAmount());
		p.setBuyerPayAmount(p.getFreeAmount());
		p.setStatus(CommonConstaints.REC_CHANNEL_PAY_STATUS_FAILED);
		p.setParam1(o.getParam1());
		p.setParam2(o.getParam2());
		recoRecPayRepository.insertRecPay(p);
		return o;
	}
	
	/**
	 * 6 记录条形码支付成功订单
	 */
	@Transactional
	public RecoRecOfflineOrderDto barCodeSuccess(String barCode, String orderNo, String payOrderNo, String subject, String storeId,
			String expireTime, String amount, String payRemark, String deviceNo, String ip, SupportStaffDto staff,
			SupportMchRecChannelDto channel, AlipayTradePayResponse response) {
		// Step1: 获取参数
		String buyer_id = response.getBuyerUserId();
		String buyer_logon_id = response.getBuyerLogonId();
		String receipt_amount = response.getReceiptAmount();
		String buyer_pay_amount = response.getBuyerPayAmount();
		Date gmt_payment = response.getGmtPayment();
		
		// Step2: 提取出关键变量并进行计算
		RecoRecPayDto p = new RecoRecPayDto();
		p.setPayOrderNo(payOrderNo);
		p.setParam1(barCode);
		p.setPayTime(DateUtil.format(gmt_payment, "yyyy:MM:dd HH:mm:ss"));
		p.setReceiptAmount(new BigDecimal(receipt_amount)); // 商户实收
		p.setFreeAmount(BigDecimalUtil.sub(p.getTotalAmount(), p.getReceiptAmount())); // 商户优惠 = 总金额 - 商户实收
		p.setBuyerPayAmount(new BigDecimal(buyer_pay_amount)); // 买家实付
		p.setThirdFreeAmount(BigDecimalUtil.sub(p.getReceiptAmount(), p.getBuyerPayAmount())); // 接口优惠 = 商户实收 - 买家实付
		p.setBuyerLogonId(buyer_logon_id);
		p.setBuyerUserId(buyer_id);
		p.setStatus(CommonConstaints.REC_CHANNEL_PAY_STATUS_SUCCESS);
		p.setChannelName(channel.getChannelName());
		p.setTotalAmount(new BigDecimal(amount));
		p.setContractName(channel.getContractName());
		p.setProductNo(channel.getProductNo());
		p.setContractId(channel.getContractId());
		p.setProductName(channel.getProductName());
		p.setPayWay(channel.getPayWay());
		p.setPayType(channel.getPayType());
		p.setContractType(channel.getContractType());
		p.setChannelNo(channel.getChannelNo());
		p.setContractNo(channel.getContractNo());
		p.setOrderNo(orderNo);
		p.setChannelId(channel.getId());
		recoRecPayRepository.updateRecPay(p);
		
		RecoRecOfflineOrderDto o = new RecoRecOfflineOrderDto();
		o.setOrderNo(orderNo);
		o.setReceiptAmount(p.getReceiptAmount());
		o.setCanRefundAmount(o.getTotalAmount());
		o.setFreeAmount(p.getFreeAmount());
		o.setLastPayTime(p.getPayTime());
		o.setParam1(barCode);
		o.setStatus(CommonConstaints.REC_ORDER_STATUS_SUCCESS);
		o.setAgentName(staff.getAgentName());
		o.setShopName(staff.getShopName());
		o.setShopId(staff.getShopId());
		o.setAgentId(staff.getAgentId());
		o.setMchId(staff.getMchId());
		o.setMchName(staff.getMerchantName());
		o.setTotalAmount(new BigDecimal(amount));
		o.setClientIp(ip);
		o.setDeviceNo(deviceNo);
		o.setSubject(subject);
		o.setReceiptRefundAmount(new BigDecimal(0));
		o.setCanRefundAmount(o.getTotalAmount());
		o.setPayCashierName(staff.getNickName()==null?staff.getMobile()==null?staff.getEmail():staff.getMobile():staff.getNickName());
		o.setPayRemark(payRemark);
		o.setRefundAmount(new BigDecimal(0));
		o.setExpireTime(expireTime);
		o.setLastPayTime(p.getPayTime());
		o.setPayCashierId(staff.getId());
		o.setPay(p);
		recoRecOfflineOrderRepository.updateRecOfflineOrder(o);
		
		// Step3: 支付成功记录交易流水
		RecoRecFlowDto flow = new RecoRecFlowDto();
		flow.setFlowNo(idUtils.getNextId());
		flow.setTradeNo(p.getPayOrderNo());
		flow.setAgentId(o.getAgentId());
		flow.setAgentName(o.getAgentName());
		flow.setChannelId(p.getChannelId());
		flow.setChannelName(p.getChannelName());
		flow.setChannelNo(p.getChannelNo());
		flow.setContractId(p.getContractId());
		flow.setContractName(p.getContractName());
		flow.setContractNo(p.getContractNo());
		flow.setContractType(p.getContractType());
		flow.setMchId(o.getMchId());
		flow.setMchName(o.getMchName());
		flow.setOrderNo(o.getOrderNo());
		flow.setPayType(p.getPayType());
		flow.setPayWay(p.getPayWay());
		flow.setProductName(p.getProductName());
		flow.setProductNo(p.getProductNo());
		flow.setShopId(o.getShopId());
		flow.setShopName(o.getShopName());
		flow.setTradeAmount(p.getTotalAmount());
		flow.setTradeTime(p.getPayTime());
		flow.setTradeType(CommonConstaints.TRADE_TYPE_REC_PAY);
		
		// 查询出支付商户合同信息
		SupportMchRecContractDto contract = supportMchRecContractService.getMerchantReceiveContract(p.getContractId());
		Assert.notNull(contract, "商户收款合同不存在");
		
		flow.setSettleStatus(CommonConstaints.SETTLE_STATUS_INIT);
		flow.setSettleType(contract.getSettleType());
		flow.setSettleRate(contract.getRate());
		flow.setSettleRiskDay(contract.getRiskDay());
		flow.setSettleDate(DateUtil.getAfterDate(new Date(), 0, flow.getSettleRiskDay(), 0, 0, 0));
		if(CommonConstaints.SETTLE_TYPE_SOLID.equals(flow.getSettleType())){
			flow.setSettleAgentRate(new BigDecimal(0));
			flow.setSettlePlatformRate(new BigDecimal(0));
			flow.setSettleAgentFee(contract.getAgentFee()); 
			flow.setSettlePlatformFee(contract.getPlatformFee());
			flow.setSettlePlatformProfit(flow.getSettlePlatformFee());
			flow.setSettleAgentProfit(flow.getSettleAgentFee());
		} else {
			flow.setSettleAgentFee(new BigDecimal(0)); 
			flow.setSettlePlatformFee(new BigDecimal(0));
			flow.setSettleAgentRate(contract.getAgentRate());
			flow.setSettlePlatformRate(contract.getPlatformRate());
			flow.setSettlePlatformProfit(BigDecimalUtil.mul(flow.getTradeAmount(), flow.getSettlePlatformRate()));
			flow.setSettleAgentProfit(BigDecimalUtil.mul(flow.getTradeAmount(), flow.getSettleAgentRate()));
		}
		flow.setSettleProfit(BigDecimalUtil.mul(flow.getTradeAmount(), contract.getRate()));
		flow.setSettleMchProfit(BigDecimalUtil.sub(flow.getTradeAmount(), BigDecimalUtil.add(flow.getSettlePlatformProfit(), flow.getSettleAgentProfit())));
		recoRecFlowRepository.insertRecFlow(flow);	
		return o;
	}
	
	/**
	 * 1 记录轮询撤销
	 */
	@Transactional
	public void pollingCancel(RecoRecPayDto payOrder, AlipayTradeCancelResponse response) {
		// Step1: 生成订单
		RecoRecOfflineOrderDto o = new RecoRecOfflineOrderDto();
		o.setOrderNo(payOrder.getOrderNo());
		o.setStatus(CommonConstaints.REC_ORDER_STATUS_CANCEL);
		recoRecOfflineOrderRepository.updateRecOfflineOrder(o);
		
		// Step3: 生成支付订单
		RecoRecPayDto p = new RecoRecPayDto();
		p.setPayOrderNo(payOrder.getPayOrderNo());
		p.setStatus(CommonConstaints.REC_CHANNEL_PAY_STATUS_CREATE);
		recoRecPayRepository.updateRecPay(p);
	}

	/**
	 * 2 记录异常订单
	 */
	@Transactional
	public void pollingCancelFailed(RecoRecPayDto payOrder, AlipayTradeQueryResponse response) {
		// Step1: 生成订单
		RecoRecOfflineOrderDto o = new RecoRecOfflineOrderDto();
		o.setOrderNo(payOrder.getOrderNo());
		o.setStatus(CommonConstaints.REC_ORDER_STATUS_FAILED);
		o.setParam1(StringUtil.substring(response.getSubCode(),50));
		o.setParam2(StringUtil.substring(response.getSubMsg(),50));
		o.setIsManual(1);
		recoRecOfflineOrderRepository.updateRecOfflineOrder(o);
		
		// Step3: 生成支付订单
		RecoRecPayDto p = new RecoRecPayDto();
		p.setPayOrderNo(payOrder.getPayOrderNo());
		p.setStatus(CommonConstaints.REC_CHANNEL_PAY_STATUS_FAILED);
		p.setParam1(o.getParam1());
		p.setParam2(o.getParam2());
		o.setIsManual(1);
		recoRecPayRepository.updateRecPay(p);
	}
	
	/**
	 * 3 记录支付成功
	 */
	public void pollingSuccess(RecoRecPayDto payOrder, AlipayTradeQueryResponse response) {
		// Step1: 获取参数
		String buyer_id = response.getBuyerUserId();
		String buyer_logon_id = response.getBuyerLogonId();
		String receipt_amount = response.getReceiptAmount();
		String buyer_pay_amount = response.getBuyerPayAmount();
		Date gmt_payment = new Date();
		
		// Step2: 提取出关键变量并进行计算
		String payOrderNo = payOrder.getPayOrderNo();
		RecoRecPayDto p = extendRecoRecPayDao.extendFindReceivePayByPayOrderNo(payOrderNo);
		Asserts.notNull(p, "渠道订单不存在！");
		RecoRecOfflineOrderDto o = extendRecoRecOfflineOrderDao.extendFindOfflineOrderByOrderNo(p.getOrderNo());
		Asserts.notNull(o, "订单不存在！");
		if(!CommonConstaints.REC_ORDER_STATUS_PAYING.equals(o.getStatus())) {
			// 只处理支付中的订单
			return;
		}
		
		// Step3: 提取出关键变量并进行计算
		p.setParam1(payOrder.getParam1());
		p.setPayTime(DateUtil.format(gmt_payment));
		p.setReceiptAmount(new BigDecimal(receipt_amount)); // 商户实收
		p.setFreeAmount(BigDecimalUtil.sub(p.getTotalAmount(), p.getReceiptAmount())); // 商户优惠 = 总金额 - 商户实收
		p.setBuyerPayAmount(new BigDecimal(buyer_pay_amount)); // 买家实付
		p.setThirdFreeAmount(BigDecimalUtil.sub(p.getReceiptAmount(), p.getBuyerPayAmount())); // 接口优惠 = 商户实收 - 买家实付
		p.setBuyerLogonId(buyer_logon_id);
		p.setBuyerUserId(buyer_id);
		p.setStatus(CommonConstaints.REC_CHANNEL_PAY_STATUS_SUCCESS);
		recoRecPayRepository.updateRecPay(p);
		
		o.setParam1(p.getParam1());
		o.setReceiptAmount(p.getReceiptAmount());
		o.setCanRefundAmount(o.getTotalAmount());
		o.setFreeAmount(p.getFreeAmount());
		o.setLastPayTime(DateUtil.format(gmt_payment));
		o.setStatus(CommonConstaints.REC_ORDER_STATUS_SUCCESS);
		o.setPay(p);
		recoRecOfflineOrderRepository.updateRecOfflineOrder(o);
		
		// Step3: 支付成功记录交易流水
		RecoRecFlowDto flow = new RecoRecFlowDto();
		flow.setFlowNo(idUtils.getNextId());
		flow.setTradeNo(p.getPayOrderNo());
		flow.setAgentId(o.getAgentId());
		flow.setAgentName(o.getAgentName());
		flow.setChannelId(p.getChannelId());
		flow.setChannelName(p.getChannelName());
		flow.setChannelNo(p.getChannelNo());
		flow.setContractId(p.getContractId());
		flow.setContractName(p.getContractName());
		flow.setContractNo(p.getContractNo());
		flow.setContractType(p.getContractType());
		flow.setMchId(o.getMchId());
		flow.setMchName(o.getMchName());
		flow.setOrderNo(o.getOrderNo());
		flow.setPayType(p.getPayType());
		flow.setPayWay(p.getPayWay());
		flow.setProductName(p.getProductName());
		flow.setProductNo(p.getProductNo());
		flow.setShopId(o.getShopId());
		flow.setShopName(o.getShopName());
		flow.setTradeAmount(p.getTotalAmount());
		flow.setTradeTime(p.getPayTime());
		flow.setTradeType(CommonConstaints.TRADE_TYPE_REC_PAY);
		
		// 查询出支付商户合同信息
		SupportMchRecContractDto contract = supportMchRecContractService.getMerchantReceiveContract(p.getContractId());
		Assert.notNull(contract, "商户收款合同不存在");
		
		flow.setSettleStatus(CommonConstaints.SETTLE_STATUS_INIT);
		flow.setSettleType(contract.getSettleType());
		flow.setSettleRate(contract.getRate());
		flow.setSettleRiskDay(contract.getRiskDay());
		flow.setSettleDate(DateUtil.getAfterDate(new Date(), 0, flow.getSettleRiskDay(), 0, 0, 0));
		if(CommonConstaints.SETTLE_TYPE_SOLID.equals(flow.getSettleType())){
			flow.setSettleAgentRate(new BigDecimal(0));
			flow.setSettlePlatformRate(new BigDecimal(0));
			flow.setSettleAgentFee(contract.getAgentFee()); 
			flow.setSettlePlatformFee(contract.getPlatformFee());
			flow.setSettlePlatformProfit(flow.getSettlePlatformFee());
			flow.setSettleAgentProfit(flow.getSettleAgentFee());
		} else {
			flow.setSettleAgentFee(new BigDecimal(0)); 
			flow.setSettlePlatformFee(new BigDecimal(0));
			flow.setSettleAgentRate(contract.getAgentRate());
			flow.setSettlePlatformRate(contract.getPlatformRate());
			flow.setSettlePlatformProfit(BigDecimalUtil.mul(flow.getTradeAmount(), flow.getSettlePlatformRate()));
			flow.setSettleAgentProfit(BigDecimalUtil.mul(flow.getTradeAmount(), flow.getSettleAgentRate()));
		}
		flow.setSettleProfit(BigDecimalUtil.mul(flow.getTradeAmount(), contract.getRate()));
		flow.setSettleMchProfit(BigDecimalUtil.sub(flow.getTradeAmount(), BigDecimalUtil.add(flow.getSettlePlatformProfit(), flow.getSettleAgentProfit())));
		recoRecFlowRepository.insertRecFlow(flow);	
	}

}
